﻿using DiLe.Mes.Application.Cloud.Dashboard;
using DiLe.Mes.Cloud.Controllers.Dashboard.Dto;
using DiLe.Mes.Model.Cloud.Dashboard.Entity;
using Microsoft.AspNetCore.Authorization;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using System.Text.RegularExpressions;

namespace DiLe.Mes.Cloud.Controllers.Dashboard {
    /// <summary>
    /// 
    /// </summary>
    [ApiExplorerSettings(GroupName = ApiCloudGroupConst.Dashboard)]
    [AllowAnonymous]
    public class DashboardController : ApiBaseController {

        readonly Regex regex = new(@"(?<=云端Dashboard-)[^-_.]+(?=_)", RegexOptions.IgnoreCase);

        readonly Regex SheetNameRegex = new(@"(?<=-)\d+$", RegexOptions.IgnoreCase);

        private readonly DashboardClient _dashboardClient;
        /// <summary>
        /// 
        /// </summary>
        public DashboardController(DashboardClient dashboardClient) {
            _dashboardClient = dashboardClient;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        [HttpGet, AllowAnonymous]
        public ApiResult Register() {
            TcpHelper.AddClient("clern001");
            return Success();
        }

        #region 上传
        /// <summary>
        /// 上传
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult> UploadFileAsync(IFormFile file) {
            var fileName = file.FileName;
            Match _match = regex.Match(fileName);
            if (!_match.Success) {
                return Fail();
            }
            var factoryName = _match.Groups[0].Value;
            var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tempfile");
            if (!Directory.Exists(dir)) {
                Directory.CreateDirectory(dir);
            }
            var filefullPath = Path.Combine(dir, fileName);
            using (FileStream fs = new(filefullPath, FileMode.Create)) {
                file.CopyTo(fs);
                fs.Flush();
            }
            var sheetNames = MiniExcel.GetSheetNames(filefullPath);
            var config = new OpenXmlConfiguration() {
                FillMergedCells = true
            };
            var list = new List<DashboardEntity>();
            foreach (var sheetName in sheetNames) {
                var rows = MiniExcel.Query(filefullPath, sheetName: sheetName, configuration: config).Cast<IDictionary<string, object>>();
                var dic = new List<DashboardDicModel>();
                int index = 0;
                string startKey = "A";
                string productName = "";
                foreach (var row in rows) {
                    index++;
                    var checkA = row["A"] != null && row["A"].ToString()!.Contains("月份");
                    var checkB = row["B"] != null && row["B"].ToString()!.Contains("月份");
                    var checkC = row["C"] != null && row["C"].ToString()!.Contains("月份");
                    if (checkA || checkB || checkC) {
                        foreach (var item in row.Keys) {
                            if (checkA) {
                                if (item == "A") {
                                    continue;
                                }
                            } else if (checkB) {
                                startKey = "B";
                                if (item == "B" || item == "A") {
                                    continue;
                                }
                            } else {
                                startKey = "C";
                                if (item == "B" || item == "A" || item == "C") {
                                    continue;
                                }
                            }
                            var val = row[item]?.ToString();
                            if (val.IsNullOrEmpty()) {
                                continue;
                            }
                            dic.Add(new DashboardDicModel { Key = item, Month = val! });
                        }
                        break;
                    }
                }
                if (sheetName.Contains("訂單Vs.出貨數量")) {
                    productName = sheetName.Replace("訂單Vs.出貨數量", "");
                }
                rows = rows.Skip(index).ToList();
                var temps = dic.ConvertAll(x => new DashboardEntity { Month = x.Month, Name = sheetName, ProductName = productName });
                if (sheetName == "設備訂單Vs出貨數量") {
                    DealwithDashboardRows2(startKey, temps, rows, dic);
                } else {
                    DealwithDashboardRows(startKey, temps, rows, dic);
                }
                list.AddRange(temps);
            }
            await _dashboardClient.DeleteDashboardAsync(x => x.FactoryName == factoryName);
            list.ForEach(p => p.FactoryName = factoryName);
            var res = await _dashboardClient.InsertDashboardAsync(list);
            return Success();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="startKey"></param>
        /// <param name="list"></param>
        /// <param name="rows"></param>
        /// <param name="dic"></param>
        /// <returns></returns>
        private static void DealwithDashboardRows(string startKey, List<DashboardEntity> list, IEnumerable<IDictionary<string, object>> rows, List<DashboardDicModel> dic) {
            foreach (var row in rows) {
                var rowVal = row[startKey]?.ToString();
                switch (rowVal) {
                    case "訂單數量":
                    case "訂單預估目標數量":
                    case "訂單目標數量":
                    case "訂單出貨目標數量":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.OraderTargetQuantity = row[key!]?.ToInt() ?? 0;
                        }
                        break;
                    case "實際出貨數量":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.ActualQuantity = row[key!]?.ToInt() ?? 0;
                        }
                        break;
                    case "累計差異數" or "累计差异数":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.CumulativeDiffQuantity = row[key!]?.ToInt();
                        }
                        break;
                    case "累計訂單數量":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.CumulativeOrderQuantity = row[key!]?.ToInt() ?? 0;
                        }
                        break;
                    case "累計訂單出貨數量":
                    case "累計出貨數量":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.CumulativeShipmentQuantity = row[key!]?.ToInt() ?? 0;
                        }
                        break;
                    case "目標值":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.TargetQuantity = PercentageConvertDouble(row[key!]?.ToString());
                        }
                        break;
                    case "達成率":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.CompletionRate = PercentageConvertDouble(row[key!]?.ToString());
                        }
                        break;
                    case "直通率目標":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.ThroughRateTarget = PercentageConvertDouble(row[key!]?.ToString());
                        }
                        break;
                    case "實績":
                        foreach (var item in list) {
                            var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                            item.ActualPerformance = PercentageConvertDouble(row[key!]?.ToString());
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="startKey"></param>
        /// <param name="list"></param>
        /// <param name="rows"></param>
        /// <param name="dic"></param>
        /// <returns></returns>
        private static void DealwithDashboardRows2(string startKey, List<DashboardEntity> list, IEnumerable<IDictionary<string, object>> rows, List<DashboardDicModel> dic) {
            var skey = "A";
            if (startKey == "C") {
                skey = "B";
            }
            foreach (var row in rows) {
                var rVal = row[skey]?.ToString();
                var rowVal = row[startKey]?.ToString();
                if (!rowVal.IsNullOrEmpty()) {
                    rowVal = rowVal!.TrimStart().TrimEnd();
                }
                if (rVal == "AOI" && rowVal == "訂單出貨目標數量") {
                    foreach (var item in list) {
                        var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                        item.OraderTargetQuantityA = row[key!]?.ToInt() ?? 0;
                    }

                } else if (rVal == "堆疊套袋機" && rowVal == "訂單出貨目標數量") {
                    foreach (var item in list) {
                        var key = dic.FirstOrDefault(p => p.Month == item.Month)?.Key;
                        item.OraderTargetQuantityB = row[key!]?.ToInt() ?? 0;
                    }
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        private static double PercentageConvertDouble(string? val) {
            if (val == null) {
                return 0;
            }
            double ff;
            if (val!.EndsWith("%")) {
                ff = double.Parse(val.TrimEnd('%')) / 100;
            } else {
                ff = double.Parse(val);
            }
            return ff;
        }
        #endregion
        #region
        /// <summary>
        /// 
        /// </summary>
        [HttpGet]
        public async Task<ApiResult> GetChartNames() {
            var list = await _dashboardClient.GetDashboardListAsync();
            var names = list?.Select(x => x.FactoryName).Distinct().ToList();
            string[] orderArray = ["丹東銘誠", "常州誠鑫", "佛山美萬邦", "台灣聯宬", "重慶誠宗"];
            var sortedList = names!.OrderBy(s => Array.IndexOf(orderArray, s)).ToList();

            return Success(sortedList);
        }
        /// <summary>
        /// 
        /// </summary>
        [HttpGet]
        public async Task<ApiResult> GetAfterSaleChartNames() {
            var list = await _dashboardClient.GetDashboardListAsync();
            var names = list?.Select(x => x.FactoryName).Distinct().ToList();
            string[] orderArray = ["丹東銘誠", "常州誠鑫", "佛山美萬邦", "台灣聯宬", "重慶誠宗"];
            var sortedList = names!.OrderBy(s => Array.IndexOf(orderArray, s)).ToList();
            sortedList.Insert(0, "首页");
            return Success(sortedList);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="factoryName"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ApiResult> GetChartDataList(string factoryName) {
            var chartList = new List<DashboardModel>();
            var list = await _dashboardClient.GetDashboardListAsync(p => p.FactoryName == factoryName);
            var groups = list.GroupBy(x => x.Name).Select(p => (p.Key, p.ToList()));
            foreach (var group in groups) {
                var m = new DashboardModel {
                    Title = group.Key
                };
                switch (group.Key) {
                    case "累計出貨數量":
                        FillChart2(group.Item2, m);
                        break;
                    case "生產達成率":
                        FillChart3(group.Item2, m);
                        break;
                    case "生產直通率":
                        FillChart4(group.Item2, m);
                        break;
                    case "設備訂單出貨數量":
                        FillChart5(group.Item2, m);
                        break;
                    case "設備訂單Vs出貨數量":
                        FillChart6(group.Item2, m);
                        break;
                    default:
                        FillChart(group.Item2, m);
                        break;
                }
                chartList.Add(m);
            }
            return Success(chartList);
        }
        /// <summary>
        /// 包装訂單Vs出貨數量
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart(List<DashboardEntity> list, DashboardModel model) {
            string? productName = list.FirstOrDefault()?.ProductName;
            model.ChartType = "bar";
            //訂單目標數量
            var m1 = new DataItem {
                Type = "bar",
                Name = $"{productName}訂單目標數量",
                MinMaxIndex = 0
            };
            //實際出貨數量
            var m2 = new DataItem {
                Type = "bar",
                Name = $"{productName}實際出貨數量",
                MinMaxIndex = 0
            };
            //累計差異數
            var m3 = new DataItem {
                Type = "line",
                Name = "累計差異數",
                MinMaxIndex = 1
            };
            foreach (var item in list) {
                model.XAxis.Add(item.Month);
                m1.Data.Add(item.OraderTargetQuantity);
                m2.Data.Add(item.ActualQuantity);
                m3.Data.Add(item.CumulativeDiffQuantity);
            }
            var a1 = new MinMaxItem {
                Max = list.Max(p => p.OraderTargetQuantity),
                Min = list.Min(p => p.OraderTargetQuantity)
            };
            model.MinMaxArr.Add(a1);


            var a3list = list.Where(p => p.CumulativeDiffQuantity != null).Select(p => p.CumulativeDiffQuantity!.Value).ToList();
            var a3 = new MinMaxItem {
                Max = !a3list.None() ? a3list.Max() : 0,
                Min = !a3list.None() ? a3list.Min() : 0
            };
            if (a3.Max == a3.Min && a3.Max == 0) {
                a3.Max = 1;
                a3.Min = -1;
            } else if (a3.Min < 0) {
                int nNum = Math.Abs(a3.Min);
                int num = 0;
                if (nNum > a3.Max) {
                    num = DealWith(nNum);
                } else {
                    num = DealWith(a3.Max);
                }
                a3.Min = -num;
                a3.Max = num;
            }



            model.MinMaxArr.Add(a3);

            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
            model.DataArr.Add(m3);
        }
        /// <summary>
        /// 累計出貨數量
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart2(List<DashboardEntity> list, DashboardModel model) {
            model.ChartType = "line";
            //累計出貨數量
            var m2 = new DataItem {
                Type = "bar",
                Name = "累計出貨數量",
                MinMaxIndex = 0,
            };
            //累計訂單數量
            var m1 = new DataItem {
                Type = "line",
                Name = "累計訂單數量",
                MinMaxIndex = 1
            };
            foreach (var item in list) {
                if (item.CumulativeShipmentQuantity > 0) {
                    m2.Data.Add(item.CumulativeShipmentQuantity);
                } else {
                    m2.Data.Add(null);
                }
                model.XAxis.Add(item.Month);
                if (item.CumulativeOrderQuantity > 0) {
                    m1.Data.Add(item.CumulativeOrderQuantity);
                } else {
                    m1.Data.Add(null);
                }
            }
            var a1 = new MinMaxItem {
                Max = list.Max(p => p.CumulativeShipmentQuantity),
                Min = list.Min(p => p.CumulativeShipmentQuantity)
            };
            model.MinMaxArr.Add(a1);

            var a2 = new MinMaxItem {
                Max = list.Max(p => p.CumulativeOrderQuantity),
                Min = list.Min(p => p.CumulativeOrderQuantity)
            };

            model.MinMaxArr.Add(a2);


            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
        }
        /// <summary>
        /// 生產達成率
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart3(List<DashboardEntity> list, DashboardModel model) {
            model.ChartType = "line";
            //目標值
            var m1 = new DataItem {
                Type = "line",
                Suffix = "%",
                Name = "目標值",
                MinMaxIndex = 0,
            };
            //達成率
            var m2 = new DataItem {
                Type = "line",
                Suffix = "%",
                Name = "達成率",
                MinMaxIndex = 0
            };
            foreach (var item in list) {
                model.XAxis.Add(item.Month);
                if (item.TargetQuantity > 0) {
                    m1.Data.Add((int)(Math.Round(item.TargetQuantity, 2) * 100));
                } else {
                    m1.Data.Add(null);
                }
                if (item.CompletionRate > 0) {
                    m2.Data.Add((int)(Math.Round(item.CompletionRate, 2) * 100));
                } else {
                    m2.Data.Add(null);
                }

            }
            var a1 = new MinMaxItem {
                Max = 110,
                Min = 0
            };
            model.MinMaxArr.Add(a1);




            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
        }
        /// <summary>
        /// 生產直通率
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart4(List<DashboardEntity> list, DashboardModel model) {
            model.ChartType = "line";
            //直通率目標
            var m1 = new DataItem {
                Type = "line",
                Suffix = "%",
                Name = "直通率目標",
                MinMaxIndex = 0
            };
            //實績
            var m2 = new DataItem {
                Type = "line",
                Suffix = "%",
                Name = "實績",
                MinMaxIndex = 0
            };
            foreach (var item in list) {
                model.XAxis.Add(item.Month);
                if (item.ThroughRateTarget > 0) {
                    m1.Data.Add(Math.Round(item.ThroughRateTarget, 3) * 100);
                } else {
                    m1.Data.Add(null);
                }

                if (item.ActualPerformance > 0) {
                    m2.Data.Add(Math.Round(Math.Round(item.ActualPerformance, 3) * 100, 1));
                } else {
                    m2.Data.Add(null);
                }
            }
            var a1 = new MinMaxItem { Max = 120, Min = 0 };
            model.MinMaxArr.Add(a1);

            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
        }
        /// <summary>
        /// 包装訂單Vs出貨數量
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart5(List<DashboardEntity> list, DashboardModel model) {
            string? productName = list.FirstOrDefault()?.ProductName;
            model.ChartType = "bar";
            //訂單目標數量
            var m1 = new DataItem {
                Type = "bar",
                Name = $"{productName}訂單目標數量",
                MinMaxIndex = 0
            };
            //實際出貨數量
            var m2 = new DataItem {
                Type = "bar",
                Name = $"{productName}實際出貨數量",
                MinMaxIndex = 0
            };
            //累计訂單數量
            var m3 = new DataItem {
                Type = "line",
                Name = "累计訂單數量",
                MinMaxIndex = 1
            };
            foreach (var item in list) {
                model.XAxis.Add(item.Month);
                m1.Data.Add(item.OraderTargetQuantity);
                m2.Data.Add(item.ActualQuantity);
                m3.Data.Add(item.CumulativeOrderQuantity);
            }

            var a1 = new MinMaxItem {
                Max = list.Max(p => p.OraderTargetQuantity),
                Min = list.Min(p => p.OraderTargetQuantity)
            };
            model.MinMaxArr.Add(a1);



            var a3 = new MinMaxItem {
                Max = list.Max(p => p.CumulativeOrderQuantity),
                Min = list.Min(p => p.CumulativeOrderQuantity)
            };
            model.MinMaxArr.Add(a3);

            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
            model.DataArr.Add(m3);
        }
        /// <summary>
        /// 設備訂單Vs出貨數量
        /// </summary>
        /// <param name="list"></param>
        /// <param name="model"></param>
        private static void FillChart6(List<DashboardEntity> list, DashboardModel model) {
            string? productName = list.FirstOrDefault()?.ProductName;
            model.ChartType = "bar";
            //AOI
            var m1 = new DataItem {
                Type = "bar",
                Name = $"AOI",
                MinMaxIndex = 0
            };
            //堆疊套袋機
            var m2 = new DataItem {
                Type = "bar",
                Name = $"堆疊套袋機",
                MinMaxIndex = 0
            };
            foreach (var item in list) {
                model.XAxis.Add(item.Month);
                m1.Data.Add(item.OraderTargetQuantityA);
                m2.Data.Add(item.OraderTargetQuantityB);
            }
            var aList = list.Where(x => x.OraderTargetQuantityA != null).ToList() ?? new List<DashboardEntity>();
            var bList = list.Where(x => x.OraderTargetQuantityB != null).ToList() ?? new List<DashboardEntity>();
            var a1 = new MinMaxItem();
            if (!aList.None()) {
                a1.Max = aList?.Max(p => p.OraderTargetQuantityA!.Value) ?? 1;
                a1.Min = aList?.Min(p => p.OraderTargetQuantityA!.Value) ?? 0;
            }
            var a2 = new MinMaxItem();
            if (!bList.None()) {
                a2.Max = bList?.Max(p => p.OraderTargetQuantityB!.Value) ?? 1;
                a2.Min = bList?.Min(p => p.OraderTargetQuantityB!.Value) ?? 0;
            }
            if (a1.Max > a2.Max) {
                if (a1.Max > 0) {
                    a1.Max = DealWith2(a1.Max);
                }
                model.MinMaxArr.Add(a1);
            } else {
                if (a2.Max > 0) {
                    a2.Max = DealWith2(a2.Max);
                }
                model.MinMaxArr.Add(a2);
            }

            model.DataArr.Add(m1);
            model.DataArr.Add(m2);
        }
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        private static int DealWith(int number) {
            int thousands = number / 1000 * 1000;
            int remainder = number % 1000;

            if (remainder > 0) {
                thousands += 1000;
            }
            return thousands;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        private static int DealWith2(int number) {
            int thousands = number / 100 * 100;
            int remainder = number % 100;

            if (remainder > 0) {
                thousands += 100;
            }
            return thousands;
        }

    }




}
